/**
 * @author nttdocomo
 */
define(function(require) {
	aries.klass("aries.form.Labelable", aries.Class.extend({

		/**
		 * @cfg {String/String[]/Ext.XTemplate} activeErrorsTpl
		 * The template used to format the Array of error messages passed to {@link #setActiveErrors} into a single HTML
		 * string. By default this renders each message as an item in an unordered list.
		 */
		activeErrorsTpl : ['<% if(errors && errors.length){ %>', '<%_.each(errors,function(error){%><li><%=error%></li><%})%>', '<%}%>'].join(""),

		childEls : [
		/**
		 * @property {Ext.Element} labelCell
		 * The `<TD>` Element which contains the label Element for this component. Only available after the component has been rendered.
		 */'labelCell',

		/**
		 * @property {Ext.Element} labelEl
		 * The label Element for this component. Only available after the component has been rendered.
		 */
		'labelEl',

		/**
		 * @property {Ext.Element} bodyEl
		 * The div Element wrapping the component's contents. Only available after the component has been rendered.
		 */
		'bodyEl',

		/**
		 * @property {Ext.Element} errorEl
		 * The div Element that will contain the component's error message(s). Note that depending on the configured
		 * {@link #msgTarget}, this element may be hidden in favor of some other form of presentation, but will always
		 * be present in the DOM for use by assistive technologies.
		 */
		'errorEl', 'inputRow'],
		tagName : 'table',
		formItemCls : aries.baseCSSPrefix + 'form-item',
		fieldLabel : undefined,
		invalidCls : aries.baseCSSPrefix + 'form-invalid',
		labelCls : aries.baseCSSPrefix + 'form-item-label',
		labelAlign : 'left',
		labelWidth : 100,
		labelPad : 5,
		labelableRenderProps : 'fieldBodyCls,baseBodyCls',

		/**
		 * @cfg {Boolean} preventMark
		 * true to disable displaying any {@link #setActiveError error message} set on this object.
		 */
		preventMark : false,

		/**
		 * @cfg {String} baseBodyCls
		 * The CSS class to be applied to the body content element.
		 */
		baseBodyCls : aries.baseCSSPrefix + 'form-item-body',

		/**
		 * @cfg {String} errorMsgCls
		 * The CSS class to be applied to the error message element.
		 */
		errorMsgCls : aries.baseCSSPrefix + 'form-error-msg',

		/**
		 * @cfg {String} fieldBodyCls
		 * An extra CSS class to be applied to the body content element in addition to {@link #baseBodyCls}.
		 */
		fieldBodyCls : '',
		labelableRenderTpl : ['<label id="labelCell" <%=labelCellAttrs%> <%if(typeof(inputId)!=="undefined"){%> for="<%=inputId%>"<%}%>><%=fieldLabel%></label><div class="<%=baseBodyCls%> <%=fieldBodyCls%> controls"<%=fieldCellAttrs%> id="<%=id%>-bodyEl"><%=field%>', '<ul id="<%=id%>-errorEl" class="<%=errorMsgCls%>" width="<%errorIconWidth%>"></ul></div>'].join(""),

		beforeLabelableRender : function() {
			if (this.ownerLayout) {
				this.addCls(aries.baseCSSPrefix + this.ownerLayout.type + '-form-item');
			}
		},
		/**
		 * Gets the active error message for this component, if any. This does not trigger validation on its own, it merely
		 * returns any message that the component may already hold.
		 * @return {String} The active error message on the component; if there is no error, an empty string is returned.
		 */
		getActiveError : function() {
			return this.activeError || '';
		},
		getLabelableRenderData : function() {

			if (!aries.form.Labelable.errorIconWidth) {
				aries.form.Labelable.errorIconWidth = 18;
			}
			data = aries.copyTo({
				inputId : this.getInputId(),
				labelOnLeft : this.labelAlign != 'top',
				fieldLabel : this.getFieldLabel(),
				//labelCellStyle : this.getLabelCellStyle(),
				labelCellAttrs : this.getLabelCellAttrs(),
				fieldCellAttrs : this.getFieldCellAttrs(),
				//labelCls : this.getLabelCls(),
				field : this.getSubTplMarkup(),
				//labelStyle : this.getLabelStyle(),
				//bodyColspan : this.getBodyColspan(),
				errorMsgCls : this.errorMsgCls + (this.autoFitErrors ? '' : ' ' + aries.baseCSSPrefix + 'external-error-icon'),
				errorIconWidth : aries.form.Labelable.errorIconWidth
			}, this, this.labelableRenderProps, true);
			return data;
		},
		getFieldLabel : function() {
			return this.fieldLabel || '';
		},
		getLabelCellAttrs : function() {
			var labelAlign = this.labelAlign, result = '';
			if (labelAlign !== 'top') {
				result = 'valign="top" halign="' + labelAlign + '" style="width:' + (this.labelWidth + this.labelPad) + 'px"';
			}
			return result + ' class="' + aries.baseCSSPrefix + 'field-label-cell ' + this.getLabelCls() + ' control-label"';
		},
		getFieldCellAttrs:function(){
			return  ' style="margin-left:' + (this.labelWidth + 20) +'px"';
		},
		getLabelCls : function() {
			var labelCls = this.labelCls, labelClsExtra = this.getLabelClsExtra();

			return labelClsExtra ? labelCls + ' ' + labelClsExtra : labelCls;
		},
		getLabelClsExtra : function() {
			return this.labelCls + '-' + this.labelAlign
		},
		initLabelable : function() {
			this.addCls([this.formItemCls,'clearfix']);
		},

		/**
		 * @private
		 * Updates the rendered DOM to match the current activeError. This only updates the content and
		 * attributes, you'll have to call doComponentLayout to actually update the display.
		 */
		renderActiveError : function() {
			var activeError = this.getActiveError(), hasError = !!activeError;

			if (activeError !== this.lastActiveError) {
				this.trigger('errorchange', this, activeError);
				this.lastActiveError = activeError;
			}

			if (this.rendered && !this.isDestroyed && !this.preventMark) {
				// Add/remove invalid class
				this.$el[hasError ? 'addClass' : 'removeClass'](this.invalidCls);

				// Update the aria-invalid attribute
				//this.getActionEl().dom.setAttribute('aria-invalid', hasError);

				// Update the errorEl (There will only be one if msgTarget is 'side' or 'under') with the error message text
				if (this.errorEl) {
					this.errorEl.html(activeError);
				}
			}
		},

		/**
		 * Set the active error message to an Array of error messages. The messages are formatted into a single message
		 * string using the {@link #activeErrorsTpl}. Also see {@link #setActiveError} which allows setting the entire error
		 * contents with a single string. Note that this only updates the error message element's text and attributes,
		 * you'll have to call doComponentLayout to actually update the field's layout to match. If the field extends
		 * {@link Ext.form.field.Base} you should call {@link Ext.form.field.Base#markInvalid markInvalid} instead.
		 * @param {String[]} errors The error messages
		 */
		setActiveErrors : function(errors) {
			errors = $.makeArray(errors);
			this.activeError = errors[0];
			this.activeErrors = errors;
			this.activeError = this.getTpl('activeErrorsTpl').apply({
				errors : errors
			});
			this.renderActiveError();
		},

		/**
		 * Clears the active error message(s). Note that this only clears the error message element's text and attributes,
		 * you'll have to call doComponentLayout to actually update the field's layout to match. If the field extends {@link
		 * aries.form.field.Base} you should call {@link aries.form.field.Base#clearInvalid clearInvalid} instead.
		 */
		unsetActiveError : function() {
			delete this.activeError;
			delete this.activeErrors;
			this.renderActiveError();
		}
	}))
})
